﻿using System;
using System.Linq;
using System.Reflection;
using CompactMapper.Orm.UnitOfWork.Mappings;

namespace CompactMapper.Orm.UnitOfWork.Commands.Criteria
{
    internal static class CriteriaFactory
    {
        public static Criterion<T> From<T>(Queries.Criterion<T> source, TablesTree tablesTree)
        {
            switch (source.Type)
            {
                case Queries.Criterion.CriterionType.StringEquals:
                    return new StringEqualsCriterion<T>(source, tablesTree);
                case Queries.Criterion.CriterionType.StringLike:
                    return new StringLikeCriterion<T>(source, tablesTree);
                case Queries.Criterion.CriterionType.EnumEquals:
                    return new EnumEqualsCriterion<T>(source, tablesTree);
                case Queries.Criterion.CriterionType.PrimaryKeyEquals:
                    return new PrimaryKeyEqualsCriterion<T>(source, tablesTree);
                case Queries.Criterion.CriterionType.IntegerEquals:
                    return new IntegerEqualsCriterion<T>(source, tablesTree);
                case Queries.Criterion.CriterionType.LongEquals:
                    return new LongEqualsCriterion<T>(source, tablesTree);
            }
            throw new InvalidOperationException("criterion not supported");
        }

        public static Criterion From(Queries.Criterion source, Table table, TablesTree tablesTreeRoot)
        {
            var type = table.Meta.Create().GetType();
            var from = typeof (CriteriaFactory).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(
                methodInfo => methodInfo.IsGenericMethodDefinition).First();
            var genericFrom = from.MakeGenericMethod(new[] {type});
            var parameters = new object[] {source, tablesTreeRoot};
            var result = genericFrom.Invoke(null, parameters);
            return (Criterion) result;
        }
    }
}